package com.yunchao.library.socket.model.security

import com.yunchao.library.socket.constants.Values
import com.yunchao.library.socket.constants.Limits
import com.yunchao.library.socket.constants.Errors
import com.yunchao.library.socket.extensions.getByteArray
import com.yunchao.library.socket.extensions.hexString
import com.yunchao.library.socket.extensions.toReadOnlyBuffer

/**
 * 安全会话数据类
 *
 * @property type 会话类型 (1=基础会话，仅使用key；2=增强会话，使用skey和mkey)
 * @property session 会话ID
 * @property key 基础会话密钥 (type=1时使用)
 * @property skey 签名密钥 (type=2时使用)
 * @property mkey 加密密钥 (type=2时使用)
 * @property sw 状态字 (默认0x9000表示成功)
 */
data class SecuritySession(
    val type: UByte,
    val session: UByte,
    private val key: ByteArray,
    private val skey: ByteArray,
    private val mkey: ByteArray,
    val sw: UShort = Values.SW_SUCCESS
) {
    init {
        when (type) {
            TYPE_TDES_CBC -> {
                // 类型1验证(TDES-CBC模式):
                // 必须提供16字节的3DES密钥，skey和mkey必须为空
                require(key.isNotEmpty()) { "类型1会话必须提供3DES密钥" }
                require(key.size == 16) { "3DES密钥长度必须为16字节" }
                require(skey.isEmpty()) { "类型1会话不应包含签名密钥(SKey)" }
                require(mkey.isEmpty()) { "类型1会话不应包含MAC密钥(MKey)" }
                require(sw == SW_SUCCESS) { "状态字必须为0x9000" }
            }

            TYPE_CIPHER_MAC -> {
                // 类型2验证(密文+MAC方式):
                // 必须提供16字节的签名密钥和MAC密钥，基础密钥必须为空
                require(skey.isNotEmpty()) { "类型2会话必须提供签名密钥(SKey)" }
                require(skey.size == 16) { "签名密钥长度必须为16字节" }
                require(mkey.isNotEmpty()) { "类型2会话必须提供MAC密钥(MKey)" }
                require(mkey.size == 16) { "MAC密钥长度必须为16字节" }
                require(key.isEmpty()) { "类型2会话不应包含基础密钥" }
                require(sw == SW_SUCCESS) { "状态字必须为0x9000" }
            }

            else -> throw IllegalArgumentException("无效的会话类型: 0x${type.toString(16)}")
        }
    }

    /**
     * 获取基础密钥 (仅type=1时有效)
     */
    fun getKey(): ByteArray {
        check(type.toInt() == 1) { "Key is only available for type 1 sessions" }
        return key.copyOf()
    }

    /**
     * 获取签名密钥 (仅type=2时有效)
     */
    fun getSKey(): ByteArray {
        check(type.toInt() == 2) { "SKey is only available for type 2 sessions" }
        return skey.copyOf()
    }

    /**
     * 获取加密密钥 (仅type=2时有效)
     */
    fun getMKey(): ByteArray {
        check(type.toInt() == 2) { "MKey is only available for type 2 sessions" }
        return mkey.copyOf()
    }

    companion object {
        const val TYPE_TDES_CBC: UByte = 0x01u
        const val TYPE_CIPHER_MAC: UByte = 0x02u
        const val SW_SUCCESS: UShort = 0x9000u
        private const val KEY_SIZE = 16

        /**
         * 从字节数组解析安全会话
         */
        fun fromByteArray(bytes: ByteArray): SecuritySession {
            val buffer = bytes.toReadOnlyBuffer()
            val type = buffer.get().toUByte()
            val session = buffer.get().toUByte()

            return when (type) {
                TYPE_TDES_CBC -> {
                    val key = buffer.getByteArray(KEY_SIZE)
                    SecuritySession(
                        type,
                        session,
                        key,
                        byteArrayOf(),
                        byteArrayOf(),
                        buffer.short.toUShort()
                    )
                }

                TYPE_CIPHER_MAC -> {
                    val skey =buffer.getByteArray(KEY_SIZE)
                    val mkey = buffer.getByteArray(KEY_SIZE)
                    SecuritySession(
                        type,
                        session,
                        byteArrayOf(),
                        skey,
                        mkey,
                        buffer.short.toUShort()
                    )
                }

                else -> throw IllegalArgumentException("${Errors.INVALID_SESSION_TYPE}: $type")
            }
        }
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as SecuritySession
        return type == other.type &&
                session == other.session &&
                sw == other.sw &&
                key.contentEquals(other.key) &&
                skey.contentEquals(other.skey) &&
                mkey.contentEquals(other.mkey)
    }

    override fun hashCode(): Int {
        var result = type.hashCode()
        result = 31 * result + session.hashCode()
        result = 31 * result + key.contentHashCode()
        result = 31 * result + skey.contentHashCode()
        result = 31 * result + mkey.contentHashCode()
        result = 31 * result + sw.hashCode()
        return result
    }

    override fun toString(): String {
        return "SecuritySession(type=$type, session=$session, key=${key.hexString}, skey=${skey.hexString}, mkey=${mkey.hexString}, sw=$sw"
    }
}